home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus 2002 #3 / Amiga Plus CD - 2002 - No. 03.iso / AmigaPlus / Tools / Development / envCPP31 / c++ / tools / cprefs / source / boopsi.c < prev    next >
Encoding:
C/C++ Source or Header  |  2002-01-01  |  58.1 KB  |  2,125 lines

  1. #include "defs.h"
  2.  
  3. /// "prototypes"
  4.  
  5. Prototype void                     boopsi_BevelBox             (struct BoopsiContext *, struct BoopsiDevice *, struct RastPort *rast, UWORD x, UWORD y, UWORD w, UWORD h, UWORD);
  6. Prototype BOOL                     boopsi_ClipDimensions       (struct BoopsiContext *, UWORD, UWORD, UWORD *, UWORD *, UWORD *, UWORD *);
  7. Prototype struct BoopsiDevice     *boopsi_CreateDeviceContext  (struct Screen *screen, struct TextFont *font);
  8. Prototype ULONG                    boopsi_DISPOSE              (struct BoopsiContext *, Class *, Object *, Msg);
  9. Prototype void                     boopsi_FreeDeviceContext    (struct BoopsiDevice *device);
  10. Prototype __asm ULONG              boopsi_GadgetDispatch       (__A0 Class *, __A2 Object *, __A1 Msg);
  11. Prototype ULONG                    boopsi_GET                  (struct BoopsiContext *, Class *, Object *, struct opGet *);
  12. Prototype void                     boopsi_GetDimensions        (struct BoopsiContext *, struct BoopsiGadget *, UWORD *, UWORD *, UWORD *, UWORD *);
  13. Prototype void                     boopsi_GetGhostingDimensions(struct BoopsiContext *, struct BoopsiGadget *, UWORD *, UWORD *, UWORD *, UWORD *);
  14. Prototype ULONG                    boopsi_GOACTIVE             (struct BoopsiContext *, Class *, struct Gadget *, struct gpInput *);
  15. Prototype ULONG                    boopsi_GOINACTIVE           (struct BoopsiContext *, Class *, struct Gadget *, struct gpGoInactive *);
  16. Prototype ULONG                    boopsi_HANDLEINPUT          (struct BoopsiContext *, Class *, struct Gadget *, struct gpInput *);
  17. Prototype ULONG                    boopsi_HANDLEINPUT_Button   (struct BoopsiContext *, struct BoopsiGadget *, struct Gadget *, struct gpInput *);
  18. Prototype ULONG                    boopsi_HANDLEINPUT_Popup    (struct BoopsiContext *, struct BoopsiGadget *, struct Gadget *, struct gpInput *);
  19. Prototype BOOL                     boopsi_InsideBox            (struct BoopsiContext *, struct BoopsiBox *, WORD, WORD);
  20. Prototype void                     boopsi_Line3D               (struct BoopsiContext *, struct BoopsiDevice *, struct RastPort *, UWORD, UWORD, UWORD, UWORD);
  21. Prototype ULONG                    boopsi_NEW                  (struct BoopsiContext *, Class *, Object *, Msg);
  22. Prototype __stkargs void           boopsi_Notify               (struct BoopsiContext *, struct Gadget *, struct GadgetInfo *, ...);
  23. Prototype UWORD                    boopsi_RasterFit            (struct BoopsiContext *, struct BoopsiDevice *, UBYTE *, UWORD, UWORD);
  24. Prototype LONG                     boopsi_RasterLength         (struct BoopsiContext *, struct BoopsiDevice *, UBYTE *, UWORD);
  25. Prototype ULONG                    boopsi_RENDER               (struct BoopsiContext *, Class *, struct Gadget *, struct gpRender *);
  26. Prototype void                     boopsi_RenderBackground     (struct BoopsiContext *, struct BoopsiGadget *, struct Gadget *, struct GadgetInfo *, struct RastPort *);
  27. Prototype void                     boopsi_RenderButton         (struct BoopsiContext *, struct BoopsiGadget *, struct Gadget *, struct GadgetInfo *, struct RastPort *);
  28. Prototype void                     boopsi_RenderDropbox        (struct BoopsiContext *, struct BoopsiGadget *, struct Gadget *, struct GadgetInfo *, struct RastPort *);
  29. Prototype void                     boopsi_RenderFocus          (struct BoopsiContext *, struct BoopsiGadget *, struct Gadget *, struct GadgetInfo *, struct RastPort *);
  30. Prototype void                     boopsi_RenderGadget         (struct BoopsiContext *, struct BoopsiGadget *, struct Gadget *, struct GadgetInfo *, struct RastPort *);
  31. Prototype void                     boopsi_RenderGhosting       (struct BoopsiContext *, struct BoopsiGadget *, struct Gadget *, struct GadgetInfo *, struct RastPort *);
  32. Prototype UWORD                    boopsi_RenderLabel          (struct BoopsiContext *, struct BoopsiGadget *, struct RastPort *, UBYTE *, UWORD, UWORD, UWORD, UWORD, UWORD, UWORD);
  33. Prototype void                     boopsi_RenderPopupItem      (struct BoopsiContext *, struct BoopsiGadget *, UWORD);
  34. Prototype void                     boopsi_RenderPopupWindow    (struct BoopsiContext *, struct BoopsiGadget *);
  35. Prototype ULONG                    boopsi_SET                  (struct BoopsiContext *, Class *, struct Gadget *, struct opSet *);
  36. Prototype struct Window           *boopsi_ShowPopupWindow      (struct BoopsiContext *, struct BoopsiGadget *, struct Gadget *, struct GadgetInfo *);
  37.  
  38. ///
  39. /// "support"
  40.  
  41. /* ---------------------------- boopsi_CreateDeviceContext ---------------------
  42.  
  43.  Create device context
  44.  
  45. */
  46.  
  47. #define RGB_SHINE  (213L<<24)
  48. #define RGB_SHADOW (120L<<24)
  49. #define RGB_GREY   (120L<<24)
  50.  
  51. struct BoopsiDevice *
  52. boopsi_CreateDeviceContext(struct Screen *screen, struct TextFont *font)
  53. {
  54.     struct BoopsiDevice *device = NULL;
  55.  
  56.     if (screen && font)
  57.     {
  58.         struct DrawInfo *drawinfo;
  59.  
  60.         if (drawinfo = GetScreenDrawInfo(screen))
  61.         {
  62.             UWORD *pens = drawinfo->dri_Pens;
  63.  
  64.             if (device = (struct BoopsiDevice *)AllocVec(sizeof(struct BoopsiDevice), MEMF_PUBLIC | MEMF_CLEAR))
  65.             {
  66.                 WORD  *spacing;
  67.                 WORD  *kerning;
  68.                 UWORD  lochar;
  69.                 UWORD  hichar;
  70.                 UWORD  ascii;
  71.                 UWORD  xwidth;
  72.  
  73.                 device->Screen = screen;
  74.                 device->Font   = font;
  75.  
  76.                 // get font metrics
  77.  
  78.                 lochar  = (UWORD )font->tf_LoChar;
  79.                 hichar  = (UWORD )font->tf_HiChar;
  80.                 spacing = (WORD *)font->tf_CharSpace;
  81.                 kerning = (WORD *)font->tf_CharKern;
  82.  
  83.                 // get width of default glyph
  84.  
  85.                 if (font->tf_Flags & FPF_PROPORTIONAL)
  86.                     xwidth = spacing[hichar - lochar + 1] + kerning[hichar - lochar + 1];
  87.                 else
  88.                     xwidth = font->tf_XSize;
  89.  
  90.                 // build font spacing table
  91.  
  92.                 for (ascii = 0; ascii < 256; ++ascii) {
  93.  
  94.                     WORD width;
  95.  
  96.                     if ((font->tf_Flags & FPF_PROPORTIONAL) && (ascii >= lochar) && (ascii <= hichar))
  97.                         width = spacing[ascii - lochar] + kerning[ascii - lochar];
  98.                     else
  99.                         width = xwidth;
  100.  
  101.                     device->Spacing[ascii] = (width < 0) ? 0 : width;
  102.                 }
  103.  
  104.                 // allocate pens
  105.  
  106.                 device->PenBackground = pens[BACKGROUNDPEN];
  107.                 device->PenShine      = pens[SHINEPEN     ];
  108.                 device->PenShadow     = pens[SHADOWPEN    ];
  109.  
  110.                 device->Pen3DShadow = ObtainBestPen(screen->ViewPort.ColorMap, RGB_SHADOW, RGB_SHADOW, RGB_SHADOW, OBP_Precision, PRECISION_EXACT, TAG_DONE);
  111.  
  112.                 if (device->Pen3DShadow == -1)
  113.                     device->Pen3DShadow = pens[SHADOWPEN];
  114.                 else
  115.                     device->ReleasePen3DShadow = TRUE;
  116.  
  117.                 device->Pen3DShine = ObtainBestPen(screen->ViewPort.ColorMap, RGB_SHINE, RGB_SHINE, RGB_SHINE, OBP_Precision, PRECISION_EXACT, TAG_DONE);
  118.  
  119.                 if (device->Pen3DShine == -1)
  120.                     device->Pen3DShine = pens[SHINEPEN];
  121.                 else
  122.                     device->ReleasePen3DShine = TRUE;
  123.  
  124.                 device->PenInactive = ObtainBestPen(screen->ViewPort.ColorMap, RGB_GREY, RGB_GREY, RGB_GREY, OBP_Precision, PRECISION_EXACT, TAG_DONE);
  125.  
  126.                 if (device->PenInactive == device->PenBackground)
  127.                 {
  128.                     ReleasePen(screen->ViewPort.ColorMap, device->PenInactive);
  129.  
  130.                     device->PenInactive = -1;
  131.                 }
  132.  
  133.                 if (device->PenInactive == -1)
  134.                     device->PenInactive = pens[SHADOWPEN];
  135.                 else
  136.                     device->ReleasePenInactive = TRUE;
  137.  
  138.             }
  139.  
  140.             FreeScreenDrawInfo(screen, drawinfo);
  141.         }
  142.     }
  143.  
  144.     return(device);
  145. }
  146.  
  147. /* ---------------------------- boopsi_FreeDeviceContext -----------------------
  148.  
  149.  Free device context
  150.  
  151. */
  152.  
  153. void
  154. boopsi_FreeDeviceContext(struct BoopsiDevice *device)
  155. {
  156.     if (device)
  157.     {
  158.         if (device->Screen)
  159.         {
  160.             struct ColorMap *colormap = device->Screen->ViewPort.ColorMap;
  161.  
  162.             if (device->ReleasePen3DShadow)
  163.  
  164.                 ReleasePen(colormap, device->Pen3DShadow);
  165.  
  166.             if (device->ReleasePen3DShine)
  167.  
  168.                 ReleasePen(colormap, device->Pen3DShine);
  169.  
  170.             if (device->ReleasePenInactive)
  171.  
  172.                 ReleasePen(colormap, device->PenInactive);
  173.         }
  174.  
  175.         FreeVec(device);
  176.     }
  177. }
  178.  
  179. ///
  180. /// "dispatcher"
  181.  
  182. /* ----------------------------- boopsi_GadgetDispatch -------------------------
  183.  
  184.  Class dispatcher (OS entry point)
  185.  
  186. */
  187.  
  188. __asm __saveds ULONG
  189. boopsi_GadgetDispatch(__A0 Class *class, __A2 Object *object, __A1 Msg msg)
  190. {
  191.     struct BoopsiContext *context;
  192.  
  193.     if (context = (struct BoopsiContext *)class->cl_UserData)
  194.     {
  195.         ULONG retval;
  196.  
  197.         switch (msg->MethodID)
  198.         {
  199.             case OM_NEW:
  200.  
  201.                 retval = boopsi_NEW(context, class, object, msg);
  202.  
  203.                 break;
  204.  
  205.             case GM_HITTEST:
  206.  
  207.                 retval = GMR_GADGETHIT;
  208.  
  209.                 break;
  210.  
  211.             case GM_RENDER:
  212.  
  213.                 retval = boopsi_RENDER(context, class, (struct Gadget *)object, (struct gpRender *)msg);
  214.  
  215.                 break;
  216.  
  217.             case GM_GOACTIVE:
  218.  
  219.                 retval = boopsi_GOACTIVE(context, class, (struct Gadget *)object, (struct gpInput *)msg);
  220.  
  221.                 break;
  222.  
  223.             case GM_GOINACTIVE:
  224.  
  225.                 retval = boopsi_GOINACTIVE(context, class, (struct Gadget *)object, (struct gpGoInactive *)msg);
  226.  
  227.                 break;
  228.  
  229.             case GM_HANDLEINPUT:
  230.  
  231.                 retval = boopsi_HANDLEINPUT(context, class, (struct Gadget *)object, (struct gpInput *)msg);
  232.  
  233.                 break;
  234.  
  235.             case OM_UPDATE:
  236.             case OM_SET:
  237.  
  238.                 retval = boopsi_SET(context, class, (struct Gadget *)object, (struct opSet *)msg);
  239.  
  240.                 break;
  241.  
  242.             case OM_GET:
  243.  
  244.                 retval = boopsi_GET(context, class, object, (struct opGet *)msg);
  245.  
  246.                 break;
  247.  
  248.             case OM_DISPOSE:
  249.  
  250.                 retval = boopsi_DISPOSE(context, class, object, msg);
  251.  
  252.                 break;
  253.  
  254.             default:
  255.  
  256.                 retval = DoSuperMethodA(class, object, msg);
  257.  
  258.                 break;
  259.         }
  260.  
  261.         return(retval);
  262.     }
  263.     else
  264.         return(GMR_NOREUSE);
  265. }
  266.  
  267. ///
  268. /// "methods"
  269.  
  270. /* ------------------------------ boopsi_NEW -----------------------------------
  271.  
  272.  NEW method
  273.  
  274. */
  275.  
  276. ULONG
  277. boopsi_NEW(struct BoopsiContext *context, Class *class, Object *object, Msg msg)
  278. {
  279.     struct TagItem *tag;
  280.     ULONG           retval;
  281.  
  282.     retval = 0;
  283.  
  284.     if (tag = (struct TagItem *)((struct opSet *)msg)->ops_AttrList)
  285.     {
  286.         if (retval = (ULONG)DoSuperMethodA(class, object, msg))
  287.         {
  288.             struct BoopsiGadget *boopsigadget;
  289.  
  290.             if (boopsigadget = (struct BoopsiGadget *)INST_DATA(class, retval))
  291.             {
  292.                 // parse tags
  293.  
  294.                 while (tag->ti_Tag)
  295.                 {
  296.                     ULONG tagdata = tag->ti_Data;
  297.  
  298.                     switch (tag->ti_Tag)
  299.                     {
  300.                         case BOOPSI_ATTRIB_DEVICE:
  301.  
  302.                             boopsigadget->Device = (struct BoopsiDevice *)tagdata;
  303.  
  304.                             break;
  305.  
  306.                         case BOOPSI_ATTRIB_KIND:
  307.  
  308.                             boopsigadget->Kind = tagdata;
  309.  
  310.                             break;
  311.  
  312.                         case GA_Top:
  313.  
  314.                             boopsigadget->TopEdge = tagdata;
  315.  
  316.                             break;
  317.  
  318.                         case GA_Left:
  319.  
  320.                             boopsigadget->LeftEdge = tagdata;
  321.  
  322.                             break;
  323.  
  324.                         case GA_Width:
  325.  
  326.                             boopsigadget->Width = tagdata;
  327.  
  328.                             break;
  329.  
  330.                         case GA_Height:
  331.  
  332.                             boopsigadget->Height = tagdata;
  333.  
  334.                             break;
  335.  
  336.                         case GA_Disabled:
  337.  
  338.                             boopsigadget->Disabled = (BOOL)tagdata;
  339.  
  340.                             break;
  341.  
  342.                         case GTCY_Labels:
  343.  
  344.                             if (boopsigadget->Labels = (UBYTE **)tagdata)
  345.                             {
  346.                                 UBYTE **label;
  347.  
  348.                                 for (label = (UBYTE **)tagdata; *label; ++label)
  349.  
  350.                                     ++boopsigadget->Maximum;
  351.                             }
  352.  
  353.                             break;
  354.  
  355.                         case GTCY_Active:
  356.  
  357.                             boopsigadget->Active = (LONG)tagdata;
  358.  
  359.                             break;
  360.  
  361.                         case BOOPSI_ATTRIB_PLACEMENT:
  362.  
  363.                             boopsigadget->Placetext = tagdata;
  364.  
  365.                             break;
  366.  
  367.                         case BOOPSI_ATTRIB_FLAGS:
  368.  
  369.                             boopsigadget->Flags = tagdata;
  370.  
  371.                             break;
  372.                     }
  373.  
  374.                     if (tag->ti_Tag == TAG_MORE)
  375.                     {
  376.                         tag = (struct TagItem *)tag->ti_Data;
  377.                     }
  378.                     else
  379.                         ++tag;
  380.                 }
  381.  
  382.                 // request initial refresh (background is clear already, new gadgets never have the focus)
  383.  
  384.                 if (boopsigadget->Kind && boopsigadget->Width && boopsigadget->Height && boopsigadget->Device && boopsigadget->Device->Screen && boopsigadget->Device->Font)
  385.                 {
  386.                     boopsigadget->Refresh = ~(BOOPSI_REFRESHBACKGROUND | BOOPSI_REFRESHFOCUS);
  387.                 }
  388.                 else
  389.                     retval = 0;
  390.             }
  391.         }
  392.     }
  393.  
  394.     return(retval);
  395. }
  396.  
  397. /* ---------------------------- boopsi_DISPOSE ---------------------------------
  398.  
  399.  DISPOSE method
  400.  
  401. */
  402.  
  403. ULONG
  404. boopsi_DISPOSE(struct BoopsiContext *context, Class *class, Object *object, Msg msg)
  405. {
  406.     struct BoopsiGadget *boopsigadget = (struct BoopsiGadget *)INST_DATA(class, object);
  407.  
  408.     if (boopsigadget->Rectangles)
  409.     {
  410.         FreeVec(boopsigadget->Rectangles);
  411.  
  412.         boopsigadget->Rectangles = NULL;
  413.     }
  414.  
  415.     return((ULONG)DoSuperMethodA(class, object, msg));
  416. }
  417.  
  418. /* ----------------------------- boopsi_RENDER ---------------------------------
  419.  
  420.  RENDER method
  421.  
  422. */
  423.  
  424. ULONG
  425. boopsi_RENDER(struct BoopsiContext *context, Class *class, struct Gadget *gad, struct gpRender *gpr)
  426. {
  427.     struct BoopsiGadget *boopsigadget = (struct BoopsiGadget *)INST_DATA(class, (Object *)gad);
  428.  
  429.     // full redraw required (to repair damage after coming to the front) ?
  430.  
  431.     if (gpr->gpr_Redraw == GREDRAW_REDRAW)
  432.  
  433.         if (gpr->gpr_GInfo->gi_Window->Flags & WFLG_SIMPLE_REFRESH)
  434.  
  435.             boopsigadget->Refresh = BOOPSI_REFRESHALL;
  436.  
  437.     boopsi_RenderGadget(context, boopsigadget, gad, gpr->gpr_GInfo, gpr->gpr_RPort);
  438.  
  439.     return(0);
  440. }
  441.  
  442. /* ---------------------------- boopsi_GOACTIVE --------------------------------
  443.  
  444.  GOACTIVE method
  445.  
  446. */
  447.  
  448. ULONG
  449. boopsi_GOACTIVE(struct BoopsiContext *context, Class *class, struct Gadget *gad, struct gpInput *gpi)
  450. {
  451.     ULONG retval = GMR_NOREUSE;
  452.  
  453.     if ((gad->Flags & GFLG_DISABLED) == FALSE)
  454.     {
  455.         struct BoopsiGadget *boopsigadget = (struct BoopsiGadget *)INST_DATA(class, (Object *)gad);
  456.  
  457.         switch (boopsigadget->Kind)
  458.         {
  459.             case BOOPSI_DROPBOX_KIND:
  460.             case BOOPSI_BUTTON_KIND:
  461.  
  462.                 retval = boopsi_HANDLEINPUT_Button(context, boopsigadget, gad, gpi);
  463.  
  464.                 break;
  465.         }
  466.  
  467.         // show focus
  468.  
  469.         if (retval == GMR_MEACTIVE)
  470.         {
  471.             boopsigadget->State   |= BOOPSI_STATE_ACTIVE;
  472.  
  473.             boopsigadget->Refresh |= BOOPSI_REFRESHFOCUS;
  474.         }
  475.  
  476.         // make visual update by calling own GM_RENDER method
  477.  
  478.         if (boopsigadget->Refresh)
  479.  
  480.             boopsi_RenderGadget(context, boopsigadget, gad, gpi->gpi_GInfo, NULL);
  481.     }
  482.  
  483.     return(retval);
  484. }
  485.  
  486. /* -------------------------- boopsi_HANDLEINPUT -------------------------------
  487.  
  488.  HANDLEINPUT method
  489.  
  490. */
  491.  
  492. ULONG
  493. boopsi_HANDLEINPUT(struct BoopsiContext *context, Class *class, struct Gadget *gad, struct gpInput *gpi)
  494. {
  495.     struct BoopsiGadget *boopsigadget;
  496.     ULONG                retval;
  497.  
  498.     boopsigadget = (struct BoopsiGadget *)INST_DATA(class, (Object *)gad);
  499.  
  500.     switch (boopsigadget->Kind)
  501.     {
  502.         case BOOPSI_DROPBOX_KIND:
  503.         case BOOPSI_BUTTON_KIND:
  504.  
  505.             retval = boopsi_HANDLEINPUT_Button(context, boopsigadget, gad, gpi);
  506.  
  507.             break;
  508.  
  509.         default:
  510.  
  511.             retval = GMR_MEACTIVE;
  512.     }
  513.  
  514.     // make visual update by calling own GM_RENDER method
  515.  
  516.     if (boopsigadget->Refresh)
  517.  
  518.         boopsi_RenderGadget(context, boopsigadget, gad, gpi->gpi_GInfo, NULL);
  519.  
  520.     return(retval);
  521. }
  522.  
  523. /* ------------------------------- boopsi_GOINACTIVE ---------------------------
  524.  
  525.  GOINACTIVE method
  526.  
  527. */
  528.  
  529. ULONG
  530. boopsi_GOINACTIVE(struct BoopsiContext *context, Class *class, struct Gadget *gad, struct gpGoInactive *gpgi)
  531. {
  532.     struct BoopsiGadget *boopsigadget = (struct BoopsiGadget *)INST_DATA(class, (Object *)gad);
  533.  
  534.     // close popup window
  535.  
  536.     if (boopsigadget->Window)
  537.     {
  538.         CloseWindow(boopsigadget->Window);
  539.  
  540.         boopsigadget->Window = NULL;
  541.     }
  542.  
  543.     // set gadget refresh
  544.  
  545.     switch (boopsigadget->Kind)
  546.     {
  547.         case BOOPSI_DROPBOX_KIND:
  548.         case BOOPSI_BUTTON_KIND:
  549.  
  550.             boopsigadget->Refresh |= BOOPSI_REFRESHBUTTON;
  551.  
  552.             break;
  553.     }
  554.  
  555.     // remove focus dashbox
  556.  
  557.     boopsigadget->State   &= ~BOOPSI_STATE_ACTIVE;
  558.  
  559.     boopsigadget->Refresh |=  BOOPSI_REFRESHFOCUS;
  560.  
  561.     boopsi_RenderGadget(context, boopsigadget, gad, gpgi->gpgi_GInfo, NULL);
  562.  
  563.     return(DoSuperMethodA(class, (Object *)gad, (Msg)gpgi));
  564. }
  565.  
  566. /* ------------------------------ boopsi_SET -----------------------------------
  567.  
  568.  SET method
  569.  
  570. */
  571.  
  572. ULONG
  573. boopsi_SET(struct BoopsiContext *context, Class *class, struct Gadget *gad, struct opSet *ops)
  574. {
  575.     struct TagItem tagarray[16];
  576.  
  577.     struct BoopsiGadget *boopsigadget;
  578.     struct TagItem      *tags;
  579.     struct TagItem      *tag;
  580.     struct TagItem      *supertag;
  581.     ULONG                retval;
  582.  
  583.     boopsigadget = (struct BoopsiGadget *)INST_DATA(class, (Object *)gad);
  584.  
  585.     // parse tag list with new attributes
  586.  
  587.     supertag = tagarray;
  588.     tags     = ops->ops_AttrList;
  589.  
  590.     while (tag = NextTagItem(&tags))
  591.     {
  592.         switch (tag->ti_Tag)
  593.         {
  594.             case GTCY_Active:
  595.  
  596.                 if (boopsigadget->Active != tag->ti_Data)
  597.                 {
  598.                     boopsigadget->Active = tag->ti_Data;
  599.  
  600.                     boopsigadget->Refresh |= BOOPSI_REFRESHACTIVE;
  601.                 }
  602.  
  603.                 break;
  604.  
  605.             case GA_Disabled:
  606.  
  607.                 if (tag->ti_Data ^ boopsigadget->Disabled)
  608.                 {
  609.                     boopsigadget->Disabled = (tag->ti_Data != FALSE);
  610.  
  611.                     if (boopsigadget->Disabled)
  612.                     {
  613.                         gad->Flags |= GFLG_DISABLED;
  614.  
  615.                         boopsigadget->Refresh |= BOOPSI_REFRESHGHOSTING;
  616.                     }
  617.                     else
  618.                     {
  619.                         gad->Flags &= ~GFLG_DISABLED;
  620.  
  621.                         boopsigadget->Refresh |= BOOPSI_REFRESHALL;
  622.                     }
  623.                 }
  624.  
  625.                 // fall through
  626.  
  627.             default:
  628.  
  629.                 *supertag++ = *tag;
  630.         }
  631.     }
  632.  
  633.     // send tag list with superclass tags (if any) to superclass
  634.  
  635.     if (supertag != tagarray)
  636.     {
  637.         struct opSet superSet;
  638.  
  639.         superSet.MethodID     = OM_SET;
  640.         superSet.ops_GInfo    = ops->ops_GInfo;
  641.         superSet.ops_AttrList = tagarray;
  642.  
  643.         // terminate superclass tags
  644.  
  645.         supertag->ti_Tag = TAG_DONE;
  646.  
  647.         retval = DoSuperMethodA(class, (Object *)gad, (Msg)&superSet);
  648.     }
  649.     else
  650.         retval = 0;
  651.  
  652.     // make visual update by calling own GM_RENDER method
  653.  
  654.     if (boopsigadget->Refresh)
  655.     {
  656.         struct RastPort *rast;
  657.  
  658.         if (rast = ObtainGIRPort(ops->ops_GInfo))
  659.         {
  660.             DoMethod((Object *)gad, GM_RENDER, ops->ops_GInfo, rast, GREDRAW_UPDATE);
  661.  
  662.             ReleaseGIRPort(rast);
  663.         }
  664.     }
  665.  
  666.     return(retval);
  667. }
  668.  
  669. /* ------------------------------ boopsi_GET -----------------------------------
  670.  
  671.  GET method
  672.  
  673. */
  674.  
  675. ULONG
  676. boopsi_GET(struct BoopsiContext *context, Class *class, Object *object, struct opGet *opg)
  677. {
  678.     struct BoopsiGadget *boopsigadget;
  679.     ULONG                retval;
  680.  
  681.     boopsigadget = (struct BoopsiGadget *)INST_DATA(class, object);
  682.  
  683.     switch (opg->opg_AttrID)
  684.     {
  685.         case GTCY_Active:
  686.  
  687.             *opg->opg_Storage = (ULONG)boopsigadget->Active;
  688.  
  689.             retval = TRUE;
  690.  
  691.             break;
  692.  
  693.         case GTCY_Labels:
  694.  
  695.             *opg->opg_Storage = (ULONG)boopsigadget->Labels;
  696.  
  697.             retval = TRUE;
  698.  
  699.             break;
  700.  
  701.         default:
  702.  
  703.             retval = DoSuperMethodA(class, object, (Msg)opg);
  704.     }
  705.  
  706.     return(retval);
  707. }
  708.  
  709. ///
  710. /// "button"
  711.  
  712. /* ------------------------------ boopsi_HANDLEINPUT_Button -------------------
  713.  
  714.  Handle input for button gadget
  715.  
  716. */
  717.  
  718. ULONG
  719. boopsi_HANDLEINPUT_Button(struct BoopsiContext *context, struct BoopsiGadget *boopsigadget, struct Gadget *gad, struct gpInput *gpi)
  720. {
  721.     ULONG retval = GMR_MEACTIVE;
  722.  
  723.     // pop-up window visible ?
  724.  
  725.     if (boopsigadget->State & BOOPSI_STATE_POPUP)
  726.     {
  727.         retval = boopsi_HANDLEINPUT_Popup(context, boopsigadget, gad, gpi);
  728.  
  729.         if (retval != GMR_MEACTIVE)
  730.         {
  731.             if (boopsigadget->Window)
  732.             {
  733.                 CloseWindow(boopsigadget->Window);
  734.  
  735.                 boopsigadget->Window = NULL;
  736.             }
  737.  
  738.             // release and refresh button
  739.  
  740.             boopsigadget->State   &= ~(BOOPSI_STATE_SELECTED | BOOPSI_STATE_POPUP);
  741.  
  742.             boopsigadget->Refresh |=  BOOPSI_REFRESHBUTTON;
  743.         }
  744.     }
  745.     else
  746.     {
  747.         struct InputEvent *ie;
  748.  
  749.         for (ie = gpi->gpi_IEvent; ie && (retval == GMR_MEACTIVE); ie = ie->ie_NextEvent)
  750.         {
  751.             switch (ie->ie_Class)
  752.             {
  753.                 case IECLASS_RAWMOUSE:
  754.  
  755.                     // pop-up menu assigned to button ?
  756.  
  757.                     if (boopsigadget->Labels)
  758.                     {
  759.                         switch (ie->ie_Code)
  760.                         {
  761.                             case SELECTDOWN:
  762.  
  763.                                 boopsigadget->Selection = UNDEFINED;
  764.  
  765.                                 boopsi_ShowPopupWindow(context, boopsigadget, gad, gpi->gpi_GInfo);
  766.  
  767.                                 break;
  768.  
  769.                             case SELECTUP:
  770.  
  771.                                 retval = GMR_NOREUSE;
  772.  
  773.                                 break;
  774.                         }
  775.                     }
  776.                     else
  777.                     {
  778.                         switch (ie->ie_Code)
  779.                         {
  780.                             case SELECTDOWN:
  781.  
  782.                                 boopsigadget->State   |= BOOPSI_STATE_SELECTED;
  783.  
  784.                                 boopsigadget->Refresh |= BOOPSI_REFRESHBUTTON;
  785.  
  786.                                 if (boopsigadget->Flags & BOOPSI_FLAGS_GACTIMMEDIATE)
  787.                                 {
  788.                                     boopsi_Notify(context, gad, gpi->gpi_GInfo, BOOPSI_ATTRIB_ADDRESS, gad, TAG_DONE);
  789.  
  790.                                     retval = GMR_NOREUSE;
  791.                                 }
  792.  
  793.                                 break;
  794.  
  795.                             case SELECTUP:
  796.  
  797.                                 if ((boopsigadget->Flags & BOOPSI_FLAGS_GACTIMMEDIATE) == FALSE)
  798.                                 {
  799.                                     boopsi_Notify(context, gad, gpi->gpi_GInfo, BOOPSI_ATTRIB_ADDRESS, gad, TAG_DONE);
  800.  
  801.                                     retval = GMR_NOREUSE;
  802.                                 }
  803.  
  804.                                 // release and refresh button
  805.  
  806.                                 boopsigadget->State   &= ~(BOOPSI_STATE_SELECTED | BOOPSI_STATE_POPUP);
  807.  
  808.                                 boopsigadget->Refresh |=  BOOPSI_REFRESHBUTTON;
  809.  
  810.                                 break;
  811.                         }
  812.                     }
  813.  
  814.                     break;
  815.             }
  816.         }
  817.     }
  818.  
  819.     return(retval);
  820. }
  821.  
  822. ///
  823. /// "messages"
  824.  
  825. /* --------------------------------- boopsi_Notify -----------------------------
  826.  
  827.  Send taglist to application (the app will receive it as IDCMP_IDCMPUPDATE
  828.  message).
  829.  
  830. */
  831.  
  832. __stkargs void
  833. boopsi_Notify(struct BoopsiContext *context, struct Gadget *gad, struct GadgetInfo *gadInfo, ...)
  834. {
  835.     struct TagItem *tags = (struct TagItem *)(&gadInfo + 1);
  836.  
  837.     DoMethod((Object *)gad, OM_NOTIFY, tags, gadInfo, 0);
  838. }
  839.  
  840. ///
  841. /// "rendering"
  842.  
  843. /* ------------------------------ RenderGadget ---------------------------------
  844.  
  845.  Render boopsigadget gadget (rast may be NULL).
  846.  
  847. */
  848.  
  849. void
  850. boopsi_RenderGadget(struct BoopsiContext *context, struct BoopsiGadget *boopsigadget, struct Gadget *gad, struct GadgetInfo *gadInfo, struct RastPort *rast)
  851. {
  852.     if (boopsigadget->Refresh)
  853.     {
  854.         BOOL obtainGIRPort;
  855.  
  856.         if (obtainGIRPort = (rast == NULL))
  857.  
  858.             rast = ObtainGIRPort(gadInfo);
  859.  
  860.         if (rast)
  861.         {
  862.             SetFont(rast, boopsigadget->Device->Font);
  863.  
  864.             // erase focus
  865.  
  866.             if ((boopsigadget->State & BOOPSI_STATE_ACTIVE) == 0)
  867.  
  868.                 boopsi_RenderFocus(context, boopsigadget, gad, gadInfo, rast);
  869.  
  870.             boopsi_RenderBackground(context, boopsigadget, gad, gadInfo, rast);
  871.  
  872.             switch (boopsigadget->Kind)
  873.             {
  874.                 case BOOPSI_DROPBOX_KIND:
  875.  
  876.                     boopsi_RenderDropbox(context, boopsigadget, gad, gadInfo, rast);
  877.  
  878.                     break;
  879.  
  880.                 case BOOPSI_BUTTON_KIND:
  881.  
  882.                     boopsi_RenderButton(context, boopsigadget, gad, gadInfo, rast);
  883.  
  884.                     break;
  885.             }
  886.  
  887.             // show focus
  888.  
  889.             if (boopsigadget->State & BOOPSI_STATE_ACTIVE)
  890.  
  891.                 boopsi_RenderFocus(context, boopsigadget, gad, gadInfo, rast);
  892.  
  893.             boopsi_RenderGhosting(context, boopsigadget, gad, gadInfo, rast);
  894.  
  895.             if (obtainGIRPort)
  896.  
  897.                 ReleaseGIRPort(rast);
  898.  
  899.             // everything refreshed
  900.  
  901.             boopsigadget->Refresh = FALSE;
  902.         }
  903.     }
  904. }
  905.  
  906.  
  907. /* ----------------------------- boopsi_RenderFocus ----------------------------
  908.  
  909.  Render or erase focus dashbox
  910.  
  911. */
  912.  
  913. void
  914. boopsi_RenderFocus(struct BoopsiContext *context, struct BoopsiGadget *boopsigadget, struct Gadget *gad, struct GadgetInfo *gadInfo, struct RastPort *rast)
  915. {
  916.     if (boopsigadget->Refresh & BOOPSI_REFRESHFOCUS)
  917.     {
  918.         if (boopsigadget->Flags & BOOPSI_FLAGS_CAPTUREFOCUS)
  919.         {
  920.             BOOL renderbox = boopsigadget->DashedW && boopsigadget->DashedH;
  921.  
  922.             if (renderbox)
  923.             {
  924.                 if (boopsigadget->State & BOOPSI_STATE_ACTIVE)
  925.                 {
  926.                     boopsi_BevelBox(context, boopsigadget->Device, rast, boopsigadget->DashedX, boopsigadget->DashedY, boopsigadget->DashedW, boopsigadget->DashedH, BOOPSI_BEVELBOXMODE_THIN | BOOPSI_BEVELBOXMODE_DASHED);
  927.                 }
  928.                 else
  929.                 {
  930.                     boopsi_BevelBox(context, boopsigadget->Device, rast, boopsigadget->DashedX, boopsigadget->DashedY, boopsigadget->DashedW, boopsigadget->DashedH, BOOPSI_BEVELBOXMODE_THIN | BOOPSI_BEVELBOXMODE_ERASE);
  931.  
  932.                     // repair ghosting
  933.  
  934.                     if (boopsigadget->Disabled)
  935.  
  936.                         boopsigadget->Refresh |= BOOPSI_REFRESHGHOSTING;
  937.                 }
  938.             }
  939.         }
  940.  
  941.         boopsigadget->Refresh &= ~BOOPSI_REFRESHFOCUS;
  942.     }
  943. }
  944.  
  945.  
  946. /* -------------------------- boopsi_RenderBackground --------------------------
  947.  
  948.  Clear gadget background with color 0
  949.  
  950. */
  951.  
  952. void
  953. boopsi_RenderBackground(struct BoopsiContext *context, struct BoopsiGadget *boopsigadget, struct Gadget *gad, struct GadgetInfo *gadInfo, struct RastPort *rast)
  954. {
  955.     if (boopsigadget->Refresh & BOOPSI_REFRESHBACKGROUND)
  956.     {
  957.         struct Window *win;
  958.         UWORD          x;
  959.         UWORD          y;
  960.         UWORD          w;
  961.         UWORD          h;
  962.  
  963.         boopsi_GetDimensions(context, boopsigadget, &x, &y, &w, &h);
  964.  
  965.         // clip at window borders
  966.  
  967.         win = gadInfo->gi_Window;
  968.  
  969.         if (boopsi_ClipDimensions(context, win->Width -  1 - win->BorderRight, win->Height - 1 - win->BorderBottom, &x, &y, &w, &h))
  970.         {
  971.             SetAPen(rast, boopsigadget->Device->PenBackground);
  972.  
  973.             RectFill(rast, x, y, x + w - 1, y + h - 1);
  974.         }
  975.  
  976.         boopsigadget->Refresh &= ~BOOPSI_REFRESHBACKGROUND;
  977.     }
  978. }
  979.  
  980.  
  981. /* -------------------------------- boopsi_RenderLabel -------------------------
  982.  
  983.  Render <label> at the specified position. You may pass in the width of a symbol
  984.  to have it considered (the function will return the symbol position).
  985.  
  986. */
  987.  
  988. UWORD
  989. boopsi_RenderLabel(struct BoopsiContext *context, struct BoopsiGadget *boopsigadget, struct RastPort *rast, UBYTE *label, UWORD placement, UWORD left, UWORD top, UWORD width, UWORD height, UWORD symbolwidth)
  990. {
  991.     UWORD imageX = left;
  992.  
  993.     if (label)
  994.     {
  995.         UWORD len;
  996.  
  997.         if (len = strlen(label))
  998.         {
  999.             UBYTE buffer[80];
  1000.  
  1001.             struct TextFont *font;
  1002.             UBYTE           *underscore;
  1003.             UWORD            labelsize;
  1004.             UWORD            fontsize;
  1005.             UWORD            x;
  1006.             UWORD            y;
  1007.             UWORD            lenA;
  1008.             UWORD            lenB;
  1009.  
  1010.             // check underscore
  1011.  
  1012.             if (underscore = strchr(label, '_'))
  1013.             {
  1014.                 // remove "_" from string
  1015.  
  1016.                 --len;
  1017.  
  1018.                 if (len > sizeof(buffer))
  1019.  
  1020.                     len = sizeof(buffer);
  1021.  
  1022.                 lenA = underscore - label;
  1023.  
  1024.                 if (lenA > sizeof(buffer))
  1025.  
  1026.                     lenA = sizeof(buffer);
  1027.  
  1028.                 lenB = len - lenA;
  1029.  
  1030.                 if (lenA)
  1031.  
  1032.                     movmem(label, buffer, lenA);
  1033.  
  1034.                 if (lenB)
  1035.  
  1036.                     movmem(label + lenA + 1, buffer + lenA, lenB);
  1037.  
  1038.                 label = buffer;
  1039.             }
  1040.  
  1041.             font     = boopsigadget->Device->Font;
  1042.             fontsize = boopsigadget->Device->Font->tf_YSize;
  1043.  
  1044.             y = top + (height - fontsize + 1) / 2;
  1045.  
  1046.             // determine labelsize
  1047.  
  1048.             labelsize = boopsi_RasterLength(context, boopsigadget->Device, label, len);
  1049.  
  1050.             // calculate position
  1051.  
  1052.             switch (placement)
  1053.             {
  1054.                 case PLACETEXT_IN:
  1055.  
  1056.                     if (symbolwidth)
  1057.                     {
  1058.                         imageX = left + 2;
  1059.  
  1060.                         x = imageX + symbolwidth + (width - symbolwidth - labelsize - 4) / 2;
  1061.                     }
  1062.                     else
  1063.                         x = left + (width  - labelsize) / 2;
  1064.  
  1065.                     break;
  1066.  
  1067.                 case PLACETEXT_LEFT:
  1068.  
  1069.                     x = left - labelsize - 8;
  1070.  
  1071.                     break;
  1072.  
  1073.                 case PLACETEXT_ABOVE:
  1074.  
  1075.                     x = left + (width - labelsize) / 2;
  1076.  
  1077.                     y = top - font->tf_YSize - 4;
  1078.  
  1079.                     break;
  1080.  
  1081.                 case PLACETEXT_BELOW:
  1082.  
  1083.                     x = left + (width - labelsize) / 2;
  1084.  
  1085.                     y = top + height + 2;
  1086.  
  1087.                     break;
  1088.  
  1089.                 default:
  1090.  
  1091.                     x = left + width + 7;
  1092.             }
  1093.  
  1094.             // dashbox not yet set ?
  1095.  
  1096.             if (boopsigadget->DashedW == 0)
  1097.             {
  1098.                 boopsigadget->DashedX = x - 1;
  1099.                 boopsigadget->DashedY = y - 1;
  1100.                 boopsigadget->DashedW = labelsize + 2;
  1101.                 boopsigadget->DashedH = fontsize  + 2;
  1102.             }
  1103.  
  1104.             y += font->tf_Baseline;
  1105.  
  1106.             Move(rast, x, y);
  1107.  
  1108.             SetAPen(rast, boopsigadget->Device->PenShadow);
  1109.             SetBPen(rast, boopsigadget->Device->PenBackground);
  1110.  
  1111.             Text(rast, label, len);
  1112.  
  1113.             if (underscore)
  1114.             {
  1115.                 labelsize = (lenA) ? boopsi_RasterLength(context, boopsigadget->Device, label, lenA) : 0;
  1116.  
  1117.                 // move underscore down (if we have free rows below the baseline)
  1118.  
  1119.                 switch (font->tf_YSize - font->tf_Baseline - 1)
  1120.                 {
  1121.                     case 0:
  1122.  
  1123.                         break;
  1124.  
  1125.                     case 1:
  1126.  
  1127.                         ++y;
  1128.  
  1129.                         break;
  1130.  
  1131.                     default:
  1132.  
  1133.                         y += 2;
  1134.  
  1135.                         break;
  1136.                 }
  1137.  
  1138.                 // render underscore
  1139.  
  1140.                 Move(rast, x + labelsize, y);
  1141.  
  1142.                 Draw(rast, rast->cp_x + boopsigadget->Device->Spacing[*(underscore + 1)] - 1, y);
  1143.             }
  1144.         }
  1145.     }
  1146.  
  1147.     return(imageX);
  1148. }
  1149.  
  1150. /* ------------------------------ RenderGhosting -------------------------------
  1151.  
  1152.  Ghost gadget
  1153.  
  1154. */
  1155.  
  1156. void
  1157. boopsi_RenderGhosting(struct BoopsiContext *context, struct BoopsiGadget *boopsigadget, struct Gadget *gad, struct GadgetInfo *gadInfo, struct RastPort *rast)
  1158. {
  1159.     if (boopsigadget->Refresh & BOOPSI_REFRESHGHOSTING)
  1160.     {
  1161.         if (boopsigadget->Disabled)
  1162.         {
  1163.             static UWORD pattern[] = { 0x4444, 0x1111 };
  1164.  
  1165.             UWORD x, y, w, h;
  1166.  
  1167.             boopsi_GetGhostingDimensions(context, boopsigadget, &x, &y, &w, &h);
  1168.  
  1169.             // ghost gadget
  1170.  
  1171.             SetAfPt(rast, pattern, 1);
  1172.  
  1173.             SetDrMd(rast, JAM1);
  1174.  
  1175.             SetAPen(rast, 1);
  1176.  
  1177.             RectFill(rast, x, y, x + w - 1, y + h - 1);
  1178.  
  1179.             SetDrMd(rast, JAM2);
  1180.  
  1181.             SetAfPt(rast, NULL, 0);
  1182.         }
  1183.  
  1184.         boopsigadget->Refresh &= ~BOOPSI_REFRESHGHOSTING;
  1185.     }
  1186. }
  1187.  
  1188. /* ------------------------------- RenderDropbox -------------------------------
  1189.  
  1190.  Render dropbox
  1191.  
  1192. */
  1193.  
  1194. #define DROPBUTTONARROWWIDTH 16
  1195.  
  1196. void
  1197. boopsi_RenderDropbox(struct BoopsiContext *context, struct BoopsiGadget *boopsigadget, struct Gadget *gad, struct GadgetInfo *gadInfo, struct RastPort *rast)
  1198. {
  1199.     if (boopsigadget->Refresh)
  1200.     {
  1201.         struct BoopsiDevice *device;
  1202.         UWORD                x;
  1203.         UWORD                y;
  1204.         UWORD                w;
  1205.         UWORD                h;
  1206.  
  1207.         device = boopsigadget->Device;
  1208.  
  1209.         // render label
  1210.  
  1211.         boopsi_GetDimensions(context, boopsigadget, &x, &y, &w, &h);
  1212.  
  1213.         if (boopsigadget->Refresh & BOOPSI_REFRESHLABEL)
  1214.         {
  1215.             boopsi_RenderLabel(context, boopsigadget, rast, (UBYTE *)gad->GadgetText, boopsigadget->Placetext, x, y, w, h, 0);
  1216.  
  1217.             boopsigadget->Refresh &= ~BOOPSI_REFRESHLABEL;
  1218.         }
  1219.  
  1220.         // render border
  1221.  
  1222.         if (boopsigadget->Refresh & BOOPSI_REFRESHDROPBOX)
  1223.         {
  1224.             static __chip UWORD planeptr[] = { 0xfe00, 0x7c00, 0x3800, 0x1000 };
  1225.  
  1226.             struct Image image;
  1227.  
  1228.             image.Width      = 7;
  1229.             image.Height     = 4;
  1230.             image.LeftEdge   = (DROPBUTTONARROWWIDTH - 7) / 2;
  1231.             image.TopEdge    = (h                    - 4) / 2;
  1232.             image.ImageData  = planeptr;
  1233.             image.Depth      = 1;
  1234.             image.PlanePick  = 1;
  1235.             image.PlaneOnOff = 1;
  1236.             image.NextImage  = NULL;
  1237.  
  1238.             // render separator line and arrow symbol
  1239.  
  1240.             boopsi_Line3D(context, device, rast, x + w - 2 - DROPBUTTONARROWWIDTH, y + 3, 0, h - 6);
  1241.  
  1242.             DrawImage(rast, &image, x + w - DROPBUTTONARROWWIDTH - 1, y);
  1243.  
  1244.             boopsigadget->Refresh &= ~BOOPSI_REFRESHDROPBOX;
  1245.         }
  1246.  
  1247.         // render active selection
  1248.  
  1249.         if (boopsigadget->Refresh & BOOPSI_REFRESHACTIVE)
  1250.         {
  1251.             // fill background
  1252.  
  1253.             SetAPen(rast, device->PenBackground);
  1254.  
  1255.             RectFill(rast, x + 2, y + 1, x + w - 3 - DROPBUTTONARROWWIDTH, y + h - 3);
  1256.  
  1257.             if (boopsigadget->Active < boopsigadget->Maximum)
  1258.             {
  1259.                 UBYTE *label;
  1260.  
  1261.                 if (label = boopsigadget->Labels[boopsigadget->Active])
  1262.                 {
  1263.                     UWORD len;
  1264.  
  1265.                     if (len = strlen(label))
  1266.                     {
  1267.                         struct TextFont *font;
  1268.                         UWORD            indent;
  1269.                         UWORD            rasterfit;
  1270.  
  1271.                         font   = device->Font;
  1272.                         indent = device->Spacing['x'];
  1273.  
  1274.                         // render active selection inside available space
  1275.  
  1276.                         rasterfit = (w - indent - DROPBUTTONARROWWIDTH - 2);
  1277.  
  1278.                         if (len = boopsi_RasterFit(context, device, label, len, rasterfit))
  1279.                         {
  1280.                             ULONG rastersize;
  1281.                             UWORD pen;
  1282.  
  1283.                             rastersize = boopsi_RasterLength(context, device, label, len);
  1284.  
  1285.                             // choose label color and style
  1286.  
  1287.                             if (boopsigadget->Active)
  1288.                             {
  1289.                                 SetSoftStyle(rast, FSF_BOLD, FSF_BOLD);
  1290.  
  1291.                                 pen = device->PenShadow;
  1292.                             }
  1293.                             else
  1294.                                 pen = device->PenInactive;
  1295.  
  1296.                             SetAPen(rast, pen);
  1297.  
  1298.                             SetBPen(rast, device->PenBackground);
  1299.  
  1300.                             // render active entry
  1301.  
  1302.                             Move(rast, x + indent + (rasterfit - rastersize) / 2, y + font->tf_Baseline + (boopsigadget->Height - font->tf_YSize) / 2);
  1303.  
  1304.                             Text(rast, label, len);
  1305.  
  1306.                             if (boopsigadget->Active)
  1307.  
  1308.                                 SetSoftStyle(rast, 0, FSF_BOLD);
  1309.                         }
  1310.                     }
  1311.                 }
  1312.             }
  1313.  
  1314.             boopsigadget->Refresh &= ~BOOPSI_REFRESHACTIVE;
  1315.         }
  1316.  
  1317.         // render knob
  1318.  
  1319.         if (boopsigadget->Refresh & BOOPSI_REFRESHBUTTON)
  1320.         {
  1321.             UWORD appearance = (boopsigadget->State & BOOPSI_STATE_SELECTED) ? BOOPSI_BEVELBOXMODE_RECESSED : BOOPSI_BEVELBOXMODE_RAISED;
  1322.  
  1323.             boopsi_BevelBox(context, device, rast, x, y, w, h, appearance);
  1324.  
  1325.             boopsigadget->Refresh &= ~BOOPSI_REFRESHBUTTON;
  1326.         }
  1327.     }
  1328. }
  1329.  
  1330. /* ------------------------------- RenderButton --------------------------------
  1331.  
  1332.  Render button
  1333.  
  1334. */
  1335.  
  1336. void
  1337. boopsi_RenderButton(struct BoopsiContext *context, struct BoopsiGadget *boopsigadget, struct Gadget *gad, struct GadgetInfo *gadInfo, struct RastPort *rast)
  1338. {
  1339.     if (boopsigadget->Refresh)
  1340.     {
  1341.         struct BoopsiDevice *device;
  1342.         UWORD                x;
  1343.         UWORD                y;
  1344.         UWORD                w;
  1345.         UWORD                h;
  1346.  
  1347.         device = boopsigadget->Device;
  1348.  
  1349.         // render label
  1350.  
  1351.         boopsi_GetDimensions(context, boopsigadget, &x, &y, &w, &h);
  1352.  
  1353.         if (boopsigadget->Refresh & BOOPSI_REFRESHLABEL)
  1354.         {
  1355.             boopsi_RenderLabel(context, boopsigadget, rast, (UBYTE *)gad->GadgetText, boopsigadget->Placetext, x, y, w, h, 0);
  1356.  
  1357.             boopsigadget->Refresh &= ~BOOPSI_REFRESHLABEL;
  1358.         }
  1359.  
  1360.         // render knob
  1361.  
  1362.         if (boopsigadget->Refresh & BOOPSI_REFRESHBUTTON)
  1363.         {
  1364.             UWORD appearance = (boopsigadget->State & BOOPSI_STATE_SELECTED) ? BOOPSI_BEVELBOXMODE_RECESSED : BOOPSI_BEVELBOXMODE_RAISED;
  1365.  
  1366.             boopsi_BevelBox(context, device, rast, x, y, w, h, appearance);
  1367.  
  1368.             boopsigadget->Refresh &= ~BOOPSI_REFRESHBUTTON;
  1369.         }
  1370.     }
  1371. }
  1372.  
  1373. ///
  1374. /// "popup"
  1375.  
  1376. /* ----------------------------- boopsi_ShowPopupWindow ------------------------
  1377.  
  1378.  Show popup menu.
  1379.  
  1380. */
  1381.  
  1382. struct Window *
  1383. boopsi_ShowPopupWindow(struct BoopsiContext *context, struct BoopsiGadget *boopsigadget, struct Gadget *gad, struct GadgetInfo *gadInfo)
  1384. {
  1385.     // count menu entries
  1386.  
  1387.     boopsigadget->Entries = 0;
  1388.  
  1389.     if (boopsigadget->Labels)
  1390.     {
  1391.         UBYTE **next;
  1392.  
  1393.         for (next = boopsigadget->Labels; *next; ++next)
  1394.  
  1395.             ++boopsigadget->Entries;
  1396.  
  1397.         // allocate layout data
  1398.  
  1399.         if (boopsigadget->Entries)
  1400.         {
  1401.             if (boopsigadget->Rectangles = (struct Rectangle *)AllocVec(boopsigadget->Entries * sizeof(struct Rectangle), MEMF_PUBLIC))
  1402.             {
  1403.                 UWORD items;
  1404.                 UWORD itemheight;
  1405.                 UWORD winwidth;
  1406.                 UWORD winheight;
  1407.                 UWORD columnsize;
  1408.                 UWORD x;
  1409.                 UWORD y;
  1410.  
  1411.                 // select dropbox gadget (now)
  1412.  
  1413.                 boopsigadget->State   |= BOOPSI_STATE_SELECTED;
  1414.                 boopsigadget->Refresh |= BOOPSI_REFRESHBUTTON;
  1415.  
  1416.                 boopsi_RenderGadget(context, boopsigadget, gad, gadInfo, NULL);
  1417.  
  1418.                 // layout menu
  1419.  
  1420.                 itemheight = boopsigadget->Device->Font->tf_YSize + 3;
  1421.                 columnsize = 0;
  1422.  
  1423.                 x = 0;
  1424.                 y = 0;
  1425.  
  1426.                 #define MAX_LINES 13
  1427.  
  1428.                 for (items = 0; items < boopsigadget->Entries; ++items)
  1429.                 {
  1430.                     UBYTE *label;
  1431.                     UWORD  len;
  1432.  
  1433.                     // continue current column ?
  1434.  
  1435.                     if (items % MAX_LINES)
  1436.                     {
  1437.                         y += itemheight;
  1438.                     }
  1439.                     else
  1440.                     {
  1441.                         x += SPACING_X + columnsize;
  1442.                         y  = SPACING_Y;
  1443.  
  1444.                         columnsize = 0;
  1445.                     }
  1446.  
  1447.                     label = boopsigadget->Labels[items];
  1448.  
  1449.                     if (len = strlen(label))
  1450.                     {
  1451.                         UWORD rastersize;
  1452.  
  1453.                         if (rastersize = boopsi_RasterLength(context, boopsigadget->Device, label, len))
  1454.                         {
  1455.                             struct Rectangle *rectangle = &boopsigadget->Rectangles[items];
  1456.  
  1457.                             rectangle->MinX = x;
  1458.                             rectangle->MinY = y;
  1459.                             rectangle->MaxX = x + rastersize - 1;
  1460.                             rectangle->MaxY = y + itemheight - 1;
  1461.  
  1462.                             if (columnsize < rastersize)
  1463.  
  1464.                                 columnsize = rastersize;
  1465.                         }
  1466.                     }
  1467.                 }
  1468.  
  1469.                 // layout window dimensions
  1470.  
  1471.                 items = (boopsigadget->Entries < MAX_LINES) ? boopsigadget->Entries : MAX_LINES;
  1472.  
  1473.                 winheight = SPACING_Y + items * itemheight + SPACING_Y;
  1474.  
  1475.                 winwidth  = SPACING_X + x + columnsize;
  1476.  
  1477.                 if (winwidth < boopsigadget->Width)
  1478.  
  1479.                     winwidth = boopsigadget->Width;
  1480.  
  1481.                 // single-column menu ?
  1482.  
  1483.                 if (boopsigadget->Entries <= MAX_LINES)
  1484.                 {
  1485.                     for (items = 0; items < boopsigadget->Entries; ++items)
  1486.  
  1487.                         boopsigadget->Rectangles[items].MaxX = winwidth - SPACING_X;
  1488.                 }
  1489.  
  1490.                 // calculate popup window position
  1491.  
  1492.                 x = gadInfo->gi_Domain.Left + boopsigadget->LeftEdge - (winwidth - boopsigadget->Width) / 2;
  1493.  
  1494.                 y = gadInfo->gi_Domain.Top  + boopsigadget->TopEdge + boopsigadget->Height;
  1495.  
  1496.                 if (gadInfo->gi_Window)
  1497.                 {
  1498.                     x += gadInfo->gi_Window->LeftEdge;
  1499.  
  1500.                     y += gadInfo->gi_Window->TopEdge;
  1501.                 }
  1502.  
  1503.                 // open popup window
  1504.  
  1505.                 boopsigadget->Window = OpenWindowTags(NULL,
  1506.  
  1507.                     WA_CustomScreen, boopsigadget->Device->Screen,
  1508.                     WA_Left,         x,
  1509.                     WA_Top,          y,
  1510.                     WA_Width,        winwidth,
  1511.                     WA_Height,       winheight,
  1512.                     WA_Borderless,   TRUE,
  1513.                     WA_RMBTrap,      TRUE,
  1514.                     WA_Activate,     FALSE,
  1515.                     WA_Flags,        0,
  1516.                     TAG_DONE
  1517.                 );
  1518.  
  1519.                 // render menu
  1520.  
  1521.                 if (boopsigadget->Window)
  1522.                 {
  1523.                     SetFont(boopsigadget->Window->RPort, boopsigadget->Device->Font);
  1524.  
  1525.                     boopsi_RenderPopupWindow(context, boopsigadget);
  1526.  
  1527.                     boopsigadget->State |= BOOPSI_STATE_POPUP;
  1528.                 }
  1529.             }
  1530.         }
  1531.     }
  1532.  
  1533.     return(boopsigadget->Window);
  1534. }
  1535.  
  1536. /* ------------------------------ RenderPopupWindow ----------------------------
  1537.  
  1538.  Render popup window
  1539.  
  1540. */
  1541.  
  1542. void
  1543. boopsi_RenderPopupWindow(struct BoopsiContext *context, struct BoopsiGadget *boopsigadget)
  1544. {
  1545.     struct Window *win;
  1546.  
  1547.     if (win = boopsigadget->Window)
  1548.     {
  1549.         struct RastPort *rast;
  1550.         UWORD            n;
  1551.  
  1552.         rast = boopsigadget->Window->RPort;
  1553.  
  1554.         // fill background
  1555.  
  1556.         SetRast(rast, boopsigadget->Device->PenShine);
  1557.  
  1558.         // draw menu border
  1559.  
  1560.         SetAPen(rast, boopsigadget->Device->PenShadow);
  1561.  
  1562.         Move(rast, 0,              0);
  1563.         Draw(rast, win->Width - 1, 0);
  1564.         Draw(rast, win->Width - 1, win->Height - 1);
  1565.         Draw(rast, 0,              win->Height - 1);
  1566.         Draw(rast, 0,              0);
  1567.  
  1568.         for (n = 0; n < boopsigadget->Entries; ++n)
  1569.  
  1570.             boopsi_RenderPopupItem(context, boopsigadget, n);
  1571.     }
  1572. }
  1573.  
  1574. /* ---------------------------- boopsi_RenderPopupItem -------------------------
  1575.  
  1576.  Render entry <n> of the popup menu
  1577.  
  1578. */
  1579.  
  1580. void
  1581. boopsi_RenderPopupItem(struct BoopsiContext *context, struct BoopsiGadget *boopsigadget, UWORD n)
  1582. {
  1583.     if (boopsigadget->Rectangles)
  1584.     {
  1585.         if (n < boopsigadget->Entries)
  1586.         {
  1587.             struct Window *win;
  1588.  
  1589.             if (win = boopsigadget->Window)
  1590.             {
  1591.                 struct BoopsiDevice *device;
  1592.                 struct RastPort     *rast;
  1593.                 struct Rectangle    *rectangle;
  1594.                 UBYTE               *label;
  1595.                 UWORD                penA;
  1596.                 UWORD                penB;
  1597.  
  1598.                 rast = win->RPort;
  1599.  
  1600.                 // choose pens (rendering active entry ?)
  1601.  
  1602.                 device = boopsigadget->Device;
  1603.  
  1604.                 if (n == boopsigadget->Selection)
  1605.                 {
  1606.                     penA = device->PenShine;
  1607.                     penB = device->PenShadow;
  1608.                 }
  1609.                 else
  1610.                 {
  1611.                     penA = device->PenShadow;
  1612.                     penB = device->PenShine;
  1613.                 }
  1614.  
  1615.                 // fill background
  1616.  
  1617.                 rectangle = &boopsigadget->Rectangles[n];
  1618.  
  1619.                 SetAPen (rast, penB);
  1620.  
  1621.                 RectFill(rast, rectangle->MinX, rectangle->MinY, rectangle->MaxX, rectangle->MaxY);
  1622.  
  1623.                 // render label
  1624.  
  1625.                 label = boopsigadget->Labels[n];
  1626.  
  1627.                 if (label && *label)
  1628.                 {
  1629.                     SetAPen(rast, penA);
  1630.                     SetBPen(rast, penB);
  1631.  
  1632.                     Move(rast, rectangle->MinX, rectangle->MinY + device->Font->tf_Baseline);
  1633.  
  1634.                     // grey out first entry ?
  1635.  
  1636.                     if ((n != 0) && (boopsigadget->Flags & BOOPSI_FLAGS_FANCY))
  1637.                     {
  1638.                         SetSoftStyle(rast, FSF_BOLD, FSF_BOLD);
  1639.                     }
  1640.  
  1641.                     Text(rast, label, strlen(label));
  1642.  
  1643.                     SetSoftStyle(rast, 0, FSF_BOLD);
  1644.                 }
  1645.             }
  1646.         }
  1647.     }
  1648. }
  1649.  
  1650. /* ---------------------------------- boopsi_Line3D ----------------------------
  1651.  
  1652.  Draw a 3D-Line (either <height> or <width> is not 0).
  1653.  
  1654. */
  1655.  
  1656. void
  1657. boopsi_Line3D(struct BoopsiContext *context, struct BoopsiDevice *device, struct RastPort *rast, UWORD xo, UWORD yo, UWORD width, UWORD height)
  1658. {
  1659.     UWORD x1, y1;
  1660.  
  1661.     if (height)
  1662.     {
  1663.         x1 = xo;
  1664.         y1 = yo + height - 1;
  1665.     }
  1666.     else
  1667.     {
  1668.         x1 = xo + width - 1;
  1669.         y1 = yo;
  1670.     }
  1671.  
  1672.     SetAPen(rast, device->Pen3DShadow);
  1673.  
  1674.     Move(rast, xo, yo);
  1675.     Draw(rast, x1, y1);
  1676.  
  1677.     if ((device->Screen->RastPort.BitMap->Depth > 1) && (device->Pen3DShine != device->Pen3DShadow))
  1678.     {
  1679.         if (height)
  1680.         {
  1681.             ++xo;
  1682.             ++x1;
  1683.         }
  1684.         else
  1685.         {
  1686.             ++yo;
  1687.             ++y1;
  1688.         }
  1689.  
  1690.         SetAPen(rast, device->Pen3DShine);
  1691.  
  1692.         Move(rast, xo, yo);
  1693.         Draw(rast, x1, y1);
  1694.     }
  1695. }
  1696.  
  1697. /* --------------------------- boopsi_HANDLEINPUT_Popup ------------------------
  1698.  
  1699.  Handle input for popup window (HANDLEINPUT)
  1700.  
  1701. */
  1702.  
  1703. ULONG
  1704. boopsi_HANDLEINPUT_Popup(struct BoopsiContext *context, struct BoopsiGadget *boopsigadget, struct Gadget *gad, struct gpInput *gpi)
  1705. {
  1706.     struct InputEvent *ie;
  1707.     UWORD              selection;
  1708.     ULONG              retval;
  1709.  
  1710.     retval = GMR_MEACTIVE;
  1711.  
  1712.     selection = boopsigadget->Selection;
  1713.  
  1714.     // process user input
  1715.  
  1716.     for (ie = gpi->gpi_IEvent; ie && (retval == GMR_MEACTIVE); ie = ie->ie_NextEvent)
  1717.     {
  1718.         switch (ie->ie_Class)
  1719.         {
  1720.             case IECLASS_RAWMOUSE:
  1721.  
  1722.                 {
  1723.                     WORD x = boopsigadget->Window->MouseX;
  1724.                     WORD y = boopsigadget->Window->MouseY;
  1725.  
  1726.                     // locate item under mouse pointer
  1727.  
  1728.                     selection = UNDEFINED;
  1729.  
  1730.                     if (boopsigadget->Rectangles)
  1731.                     {
  1732.                         UWORD item;
  1733.  
  1734.                         for (item = 0; item < boopsigadget->Entries; ++item)
  1735.                         {
  1736.                             struct Rectangle *rectangle = &boopsigadget->Rectangles[item];
  1737.  
  1738.                             if ((x >= rectangle->MinX) && (y >= rectangle->MinY) && (x < rectangle->MaxX) && (y < rectangle->MaxY))
  1739.                             {
  1740.                                 selection = item;
  1741.  
  1742.                                 break;
  1743.                             }
  1744.                         }
  1745.                     }
  1746.  
  1747.                     switch (ie->ie_Code)
  1748.                     {
  1749.                         case SELECTUP:
  1750.  
  1751.                             // button released outside popup window ?
  1752.  
  1753.                             if (boopsigadget->Selection == UNDEFINED)
  1754.                             {
  1755.                                 retval = GMR_NOREUSE;
  1756.                             }
  1757.                             else
  1758.                             {
  1759.                                 boopsigadget->Active = boopsigadget->Selection;
  1760.  
  1761.                                 switch (boopsigadget->Kind)
  1762.                                 {
  1763.                                     case BOOPSI_DROPBOX_KIND:
  1764.  
  1765.                                         boopsigadget->Refresh |= BOOPSI_REFRESHACTIVE;
  1766.  
  1767.                                         break;
  1768.                                 }
  1769.  
  1770.                                 boopsi_Notify(context, gad, gpi->gpi_GInfo, BOOPSI_ATTRIB_ADDRESS, gad, GTCY_Active, boopsigadget->Active, TAG_DONE);
  1771.  
  1772.                                 retval = GMR_NOREUSE;
  1773.                             }
  1774.  
  1775.                             break;
  1776.                     }
  1777.                 }
  1778.  
  1779.                 break;
  1780.  
  1781.             case IECLASS_RAWKEY:
  1782.  
  1783.                 switch (ie->ie_Code)
  1784.                 {
  1785.                     case CURSORDOWN:
  1786.  
  1787.                         if (selection == UNDEFINED)
  1788.  
  1789.                             selection = 0;
  1790.  
  1791.                         else if ((selection + 1) < boopsigadget->Entries)
  1792.  
  1793.                             ++selection;
  1794.  
  1795.                         break;
  1796.  
  1797.                     case CURSORUP:
  1798.  
  1799.                         if (selection == UNDEFINED)
  1800.  
  1801.                             selection = boopsigadget->Entries - 1;
  1802.  
  1803.                         else if (selection)
  1804.  
  1805.                             --selection;
  1806.  
  1807.                         break;
  1808.  
  1809.                     // ESC
  1810.  
  1811.                     case 0x45:
  1812.  
  1813.                         retval = GMR_NOREUSE;
  1814.  
  1815.                         break;
  1816.  
  1817.                     // SAPCE, TAB, CR, RETURN
  1818.  
  1819.                     case 0x40:
  1820.                     case 0x42:
  1821.                     case 0x43:
  1822.                     case 0x44:
  1823.  
  1824.                         boopsigadget->Active = boopsigadget->Selection;
  1825.  
  1826.                         boopsigadget->Refresh |= BOOPSI_REFRESHACTIVE;
  1827.  
  1828.                         boopsi_Notify(context, gad, gpi->gpi_GInfo, BOOPSI_ATTRIB_ADDRESS, gad, GTCY_Active, boopsigadget->Active, TAG_DONE);
  1829.  
  1830.                         retval = GMR_NOREUSE;
  1831.  
  1832.                         break;
  1833.                 }
  1834.  
  1835.                 break;
  1836.         }
  1837.     }
  1838.  
  1839.     // highlight current selection, hide old selection
  1840.  
  1841.     if (selection != boopsigadget->Selection)
  1842.     {
  1843.         UWORD oldactive = boopsigadget->Selection;
  1844.  
  1845.         boopsigadget->Selection = selection;
  1846.  
  1847.         boopsi_RenderPopupItem(context, boopsigadget, selection);
  1848.  
  1849.         boopsi_RenderPopupItem(context, boopsigadget, oldactive);
  1850.     }
  1851.  
  1852.     return(retval);
  1853. }
  1854.  
  1855. ///
  1856. /// "misc"
  1857.  
  1858. /* --------------------------------- boopsi_BevelBox ---------------------------
  1859.  
  1860.  DrawBevelBox() replacement (thin lines, various styles)
  1861.  
  1862. */
  1863.  
  1864. void
  1865. boopsi_BevelBox(struct BoopsiContext *context, struct BoopsiDevice *device, struct RastPort *rast, UWORD x, UWORD y, UWORD w, UWORD h, UWORD mode)
  1866. {
  1867.     if (w--)
  1868.     {
  1869.         if (h--)
  1870.         {
  1871.             UWORD xp1, xp2, xp3, yp1, yp2, xpw, xpwm1, xpwm2, xpwm3, yph, yphm1, yphm2;
  1872.  
  1873.             // layout bevel box
  1874.  
  1875.             xp1   = x   + 1;
  1876.             xp2   = xp1 + 1;
  1877.             xp3   = xp2 + 1;
  1878.  
  1879.             yp1   = y   + 1;
  1880.             yp2   = yp1 + 1;
  1881.  
  1882.             xpw   = x + w;
  1883.             xpwm1 = xpw   - 1;
  1884.             xpwm2 = xpwm1 - 1;
  1885.             xpwm3 = xpwm2 - 1;
  1886.  
  1887.             yph   = y + h;
  1888.             yphm1 = yph   - 1;
  1889.             yphm2 = yphm1 - 1;
  1890.  
  1891.             if (mode & BOOPSI_BEVELBOXMODE_AMIGA)
  1892.             {
  1893.                 SetAPen(rast, device->PenShine);
  1894.  
  1895.                 RectFill(rast, x, y, x, yph);
  1896.  
  1897.                 RectFill(rast, x, y, xpwm1, y);
  1898.  
  1899.                 RectFill(rast, xp1, yp1, xp1, yphm1);
  1900.  
  1901.                 RectFill(rast, xp3, yphm1, xpwm2, yphm1);
  1902.  
  1903.                 RectFill(rast, xpwm2, yp1, xpwm2, yphm1);
  1904.  
  1905.                 RectFill(rast, xpwm3, yp2, xpwm3, yphm2);
  1906.  
  1907.                 SetAPen(rast, device->PenShadow);
  1908.  
  1909.                 RectFill(rast, xp2, yp1, xp2, yphm1);
  1910.  
  1911.                 RectFill(rast, xp2, yp1, xpwm3, yp1);
  1912.  
  1913.                 RectFill(rast, xp1, yph, xpw, yph);
  1914.  
  1915.                 RectFill(rast, xpw, y, xpw, yph);
  1916.  
  1917.                 RectFill(rast, xpwm1, yp1, xpwm1, yphm1);
  1918.  
  1919.                 RectFill(rast, xp3, yp1, xp3, yphm2);
  1920.             }
  1921.             else
  1922.             {
  1923.                 static UWORD pattern[] = { 0xAAAA, 0x5555 };
  1924.  
  1925.                 UWORD penShadow;
  1926.                 UWORD penShine;
  1927.                 UWORD penBackground;
  1928.  
  1929.                 penShadow      = device->PenShadow;
  1930.                 penShine       = device->PenShine;
  1931.                 penBackground  = device->PenBackground;
  1932.  
  1933.                 if (mode & BOOPSI_BEVELBOXMODE_DASHED)
  1934.                 {
  1935.                     SetAfPt(rast, pattern, 1);
  1936.  
  1937.                     SetBPen(rast, penBackground);
  1938.                 }
  1939.  
  1940.                 if (mode & BOOPSI_BEVELBOXMODE_ERASE)
  1941.                 {
  1942.                     SetAPen(rast, penBackground);
  1943.                 }
  1944.                 else if (mode & (BOOPSI_BEVELBOXMODE_SOLID | BOOPSI_BEVELBOXMODE_RECESSED | BOOPSI_BEVELBOXMODE_DASHED))
  1945.                 {
  1946.                     SetAPen(rast, penShadow);
  1947.                 }
  1948.                 else
  1949.                     SetAPen(rast, penShine);
  1950.  
  1951.                 RectFill(rast, x, y, x, yph);
  1952.  
  1953.                 RectFill(rast, x, y, xpwm1, y);
  1954.  
  1955.                 if ((mode & BOOPSI_BEVELBOXMODE_THIN) == 0)
  1956.  
  1957.                     RectFill(rast, xp1, yp1, xp1, yphm1);
  1958.  
  1959.                 if (mode & BOOPSI_BEVELBOXMODE_ERASE)
  1960.                 {
  1961.                     SetAPen(rast, penBackground);
  1962.                 }
  1963.                 else if (mode & (BOOPSI_BEVELBOXMODE_SOLID | BOOPSI_BEVELBOXMODE_RAISED | BOOPSI_BEVELBOXMODE_DASHED))
  1964.                 {
  1965.                     SetAPen(rast, penShadow);
  1966.                 }
  1967.                 else
  1968.                     SetAPen(rast, penShine);
  1969.  
  1970.                 RectFill(rast, xpw, y, xpw, yph);
  1971.  
  1972.                 if ((mode & BOOPSI_BEVELBOXMODE_THIN) == 0)
  1973.  
  1974.                     RectFill(rast, xpwm1, yp1, xpwm1, yph);
  1975.  
  1976.                 RectFill(rast, xp1, yph, xpw, yph);
  1977.  
  1978.                 if (mode & BOOPSI_BEVELBOXMODE_DASHED)
  1979.  
  1980.                     SetAfPt(rast, NULL, 0);
  1981.             }
  1982.         }
  1983.     }
  1984. }
  1985.  
  1986. ///
  1987. /// "metrics"
  1988.  
  1989. /* --------------------------------- boopsi_InsideBox --------------------------
  1990.  
  1991.  Check whether (x|y) are indside the specified region
  1992.  
  1993. */
  1994.  
  1995. BOOL
  1996. boopsi_InsideBox(struct BoopsiContext *context, struct BoopsiBox *box, WORD x, WORD y)
  1997. {
  1998.     return((BOOL)((x >= box->Left) && (y >= box->Top) && (x < (box->Left + box->Width)) && (y < (box->Top + box->Height))));
  1999. }
  2000.  
  2001. /* --------------------------------- boopsi_GetDimensions ----------------------
  2002.  
  2003.  Return actual dimensions of gadget
  2004.  
  2005. */
  2006.  
  2007. void
  2008. boopsi_GetDimensions(struct BoopsiContext *context, struct BoopsiGadget *boopsigadget, UWORD *x, UWORD *y, UWORD *w, UWORD *h)
  2009. {
  2010.     *x = boopsigadget->LeftEdge;
  2011.     *y = boopsigadget->TopEdge;
  2012.     *w = boopsigadget->Width;
  2013.     *h = boopsigadget->Height;
  2014. }
  2015.  
  2016. /* ----------------------------- boopsi_GetGhostingDimensions ------------------
  2017.  
  2018.  Return dimensions of ghosting area
  2019.  
  2020. */
  2021.  
  2022. void
  2023. boopsi_GetGhostingDimensions(struct BoopsiContext *context, struct BoopsiGadget *boopsigadget, UWORD *x, UWORD *y, UWORD *w, UWORD *h)
  2024. {
  2025.     switch (boopsigadget->Kind)
  2026.     {
  2027.         case BOOPSI_DROPBOX_KIND:
  2028.         case BOOPSI_BUTTON_KIND:
  2029.  
  2030.             *x = boopsigadget->LeftEdge + 2;
  2031.             *y = boopsigadget->TopEdge  + 1;
  2032.             *w = boopsigadget->Width    - 4;
  2033.             *h = boopsigadget->Height   - 3;
  2034.  
  2035.             break;
  2036.  
  2037.         default:
  2038.  
  2039.             *x = boopsigadget->LeftEdge;
  2040.             *y = boopsigadget->TopEdge;
  2041.             *w = boopsigadget->Width;
  2042.             *h = boopsigadget->Height;
  2043.  
  2044.             break;
  2045.     }
  2046. }
  2047.  
  2048. /* ----------------------------- boopsi_ClipDimensions -------------------------
  2049.  
  2050.  Clip dimensions of box (<x>, <y>, <w>, <h>) at <xmax> and <ymax>. Return TRUE
  2051.  if box is still visible.
  2052.  
  2053. */
  2054.  
  2055. BOOL
  2056. boopsi_ClipDimensions(struct BoopsiContext *context, UWORD xmax, UWORD ymax, UWORD *x, UWORD *y, UWORD *w, UWORD *h)
  2057. {
  2058.     if ((*x <= xmax) && (*y <= ymax))
  2059.     {
  2060.         if ((*x + *w - 1) > xmax)
  2061.  
  2062.             *w = xmax - *x;
  2063.  
  2064.         if ((*y + *h - 1) > ymax)
  2065.  
  2066.             *h = ymax - *y;
  2067.     }
  2068.     else
  2069.     {
  2070.         // fully obscured
  2071.  
  2072.         *w = 0;
  2073.         *h = 0;
  2074.     }
  2075.  
  2076.     if (*w && *h)
  2077.         return(TRUE);
  2078.     else
  2079.         return(FALSE);
  2080. }
  2081.  
  2082. /* ------------------------------- boopsi_RasterLength -------------------------
  2083.  
  2084.  Determine raster lenght of a string
  2085.  
  2086. */
  2087.  
  2088. LONG
  2089. boopsi_RasterLength(struct BoopsiContext *context, struct BoopsiDevice *device, UBYTE *text, UWORD len)
  2090. {
  2091.     LONG labelsize = 0;
  2092.  
  2093.     while (len--)
  2094.  
  2095.         labelsize += device->Spacing[*text++];
  2096.  
  2097.     return(labelsize);
  2098. }
  2099.  
  2100. /* --------------------------------- boopsi_RasterFit --------------------------
  2101.  
  2102.  Determine number of characters that will fit into given extent (<width>).
  2103.  
  2104. */
  2105.  
  2106. UWORD
  2107. boopsi_RasterFit(struct BoopsiContext *context, struct BoopsiDevice *device, UBYTE *text, UWORD len, UWORD width)
  2108. {
  2109.     LONG  labelsize;
  2110.     UWORD count;
  2111.  
  2112.     for (count = 0, labelsize = 0; len--; ++count)
  2113.     {
  2114.         labelsize += device->Spacing[*text++];
  2115.  
  2116.         if (labelsize > width)
  2117.  
  2118.             return(count);
  2119.     }
  2120.  
  2121.     return(count);
  2122. }
  2123.  
  2124. ///
  2125.